#pragma once

#include "my_nvs.hpp"
#include "my_storage_manager.h"
#include <vector>
#include <esp_log.h>

#define CONFIG_NAMESPACE    "storage"           // 用于存储数据的名字空间
#define CONFIG_MAX_ITEM     CONFIG_MAX_STORAGE  // 存储最大项目数量

#define STORAGE_TAG "MyStorage"


template <typename Item>  
class MyStorage {
public:
    typedef void(*PrintItemFunc)(const Item& item);

    MyStorage(std::string prefix, const StructMeta& meta);
    ~MyStorage();

    inline size_t GetSize() const { return storage_.GetSize(); }
    inline size_t GetUsed() const { return storage_.GetUsed(); }
    // 无条件保存数据
    bool Write(const Item& item);

    // 遍历数据
    template <typename Predicate>
    bool ForeachMutable(Predicate pre, bool is_handle_first=true);
    template <typename Predicate>
    bool ForeachReadOnly(Predicate pre, bool is_handle_first=true);

    // 条件保存数据（有时修改，无时直接保存）
    template <typename Predicate>
    bool Upsert(Predicate pre, const Item& upsert_item);
    
    // 条件读取数据
    template <typename Predicate>
    bool Read(Predicate pre, Item& item);

    // 条件修改数据，全局修改还是只修改第1个
    template <typename Predicate>
    bool Modify(Predicate pre, bool is_handle_first=true);

    // 删除数据，全局删除还是单个删除
    template <typename Predicate>
    bool Del(Predicate pre, bool is_del_first=true);
    
    template <typename Predicate>
    bool Find(Predicate pre);

    // 清空数据
    bool Clear(void);
    inline void Commit() { storage_.Commit(); }

    // 用户格式化打印函数
    inline void SetPrintf(PrintItemFunc fn) {
        printf_ = fn;
    }
    inline void Printf(const Item& it) const {
        if (printf_) {
            printf_(it);
        } else {
            ESP_LOGW(STORAGE_TAG, "Set the printf function first.");
        }
    }


private:

    inline void InvalidAllCache() { cache_.valid = false; }
    inline void InvalidCacheByIndex(BitmapIndex index) { 
        if (cache_.data.index == index) {
            cache_.valid = false;
        }
    }
    inline void InvalidCacheByMask(BitmapType mask) {
        BitmapIndex index = 0;
        while (mask) {
            if (mask & 1) {
                InvalidCacheByIndex(index);
            }
            mask >>= 1;
            index++;
        }
    }

    // 缓存.........
    // 1. 最小命中作为加载对象
    // 2. 加载缓存
    // 3. 失效缓存
    struct CacheData {
        Item        item;       // 具体数据---必须在第1个，原因（后续强制转化了指针）
        BitmapIndex index;      // 在位图中的索引
    };
    struct Cache {
        bool        valid;      // 缓存有效性
        CacheData   data;       // 缓存数据......目前仅支持1个缓存数据
    };
    Cache       cache_;

    // 存储实例
    StorageManager  storage_; 
    PrintItemFunc   printf_;
};


template <typename Item>
MyStorage<Item>::MyStorage(std::string prefix, const StructMeta& meta) 
    : storage_(CONFIG_NAMESPACE, prefix, meta)
    , printf_(nullptr)
{
    cache_.valid = false;
    ESP_LOGI(STORAGE_TAG, "Inital storage ... OK.");
}

template <typename Item>
MyStorage<Item>::~MyStorage()
{}

/// @brief 无条件增加一个对象，支持重复(更新缓存)
template <typename Item>
bool MyStorage<Item>::Write(const Item& item)
{
    auto used = GetUsed();
    auto space = GetSize();
    if(used >= space) {
        ESP_LOGE(STORAGE_TAG, "Storage is full. used/space: %lu/%lu", used, space);
        return false;
    } else {
        auto index  = storage_.Add(&item);
        if (index == CONFIG_MAX_STORAGE) {
            ESP_LOGE(STORAGE_TAG, "Write item failed.");
            return false;
        }
        // 缓存策略--增加策略
        cache_.valid = true;
        cache_.data.index = index;
        cache_.data.item = item;
    }
    return true;
}

/// @brief 遍历数据（缓存存在时）
/// @param pre 用户处理函数（返回true表示修改了数据）
/// @return 匹配成功时返回true
template <typename Item>
template <typename Predicate>
bool MyStorage<Item>::ForeachMutable(Predicate pre, bool is_handle_first)
{
    Item cache_item = cache_.data.item;
    BitmapIndex hit_index;
    auto checked_cache = false;

    // 缓存处理
    if (cache_.valid) {
        checked_cache = true;
        hit_index = cache_.data.index;
        if (pre(cache_item)) {
            storage_.DifferWrite(cache_.data.index, &cache_.data.item, &cache_item);
            cache_.data.item = cache_item;
            if (is_handle_first) {
                return true;
            }
        }
    }

    // 遍历
    for (auto index = storage_.begin(); index < storage_.end(); index = storage_.next(index)) {
        if (checked_cache && index == hit_index) {
            continue;
        }
        
        // 遍历对象
        if (ESP_OK != storage_.Read(index, &cache_item)) {
            cache_.valid = false;
            continue;
        } else {
            cache_.valid = true;
            cache_.data.index = index;

            auto tmp = cache_item;
            if (pre(tmp)) {
                storage_.DifferWrite(index, &cache_item, &tmp);
                if (is_handle_first) {
                    return true;
                }
            }
        }
    }

    return false;
}

/// @brief 遍历数据（缓存存在时）
/// @param pre 用户处理函数（返回true表示处理完结）
/// @return 匹配成功时返回true
template <typename Item>
template <typename Predicate>
bool MyStorage<Item>::ForeachReadOnly(Predicate pre, bool is_handle_first)
{
    auto& item = cache_.data.item;
    BitmapIndex hit_index;

    // 缓存处理
    auto checked_cache = false;
    if (cache_.valid) {
        checked_cache = true;
        hit_index = cache_.data.index;
        if (pre(item)) {
            return is_handle_first;
        }
    }

    // 遍历
    for (auto index = storage_.begin(); index < storage_.end(); index = storage_.next(index)) {
        if (checked_cache && hit_index == index) {
            continue;
        }
        
        // 遍历对象
        if (ESP_OK != storage_.Read(index, &item)) {
            cache_.valid = false;
            continue;
        } else {
            cache_.valid = true;
            cache_.data.index = index;

            if (pre(item)) {
                return is_handle_first;
            }
        }
    }

    return false;
}


/// @brief 在对象不存在时增加对象，存在时修改其内容
/// @param pre 用户定义的判断函数（返回true表示为修改的对象）
template <typename Item>
template <typename Predicate>
bool MyStorage<Item>::Upsert(Predicate pre, const Item& upsert_item)
{
    bool found = false;
    ForeachMutable([&](Item& item) -> bool {
        if (pre(item)) {
            item = upsert_item;
            found = true;
            return true;
        }
        return false;
    }, true);
    if (!found) {
        return Write(upsert_item);
    }
    return true;
}


template <typename Item>
template <typename Predicate>
bool MyStorage<Item>::Read(Predicate pre, Item& output)
{
    auto ret = false;
    ForeachReadOnly([&](const Item& item) -> bool {
        if (pre(item)) {
            output = item;
            ret = true;
            return true;
        }
        return false;
    });

    return ret;
}

/// @brief 根据用户定义的条件删除对象（只删除第1个）
/// @param pre 用户筛选函数，返回true时为选定的删除对象。。。。删除时需要失效缓存！！！
template <typename Item>
template <typename Predicate>
bool MyStorage<Item>::Del(Predicate pre, bool is_del_first)
{
    size_t count = 0;
    BitmapType mask = 0;
    BitmapIndex index;

    ForeachReadOnly([&](const Item& item) -> bool {
        if (pre(item)) {
            index = ((const CacheData*)(&item))->index; // ...，获取它的索引
            mask |= storage_.IndexToBitmap(index);
            count ++;
            return is_del_first; 
        }
        return false;
    });

    auto err = storage_.Del(mask);
    if (err == ESP_OK) {
        ESP_LOGI(STORAGE_TAG, "In this predicate, del %d item", count);
        InvalidCacheByMask(mask);
    } else {
        ESP_LOGE(STORAGE_TAG, "Del failed, err=%s", esp_err_to_name(err));
    }

    return count != 0;
}

/// @brief 修改符合条件的对象(只修改了一个，下下要修改成可选持续修改的)
/// @param pre 用户处理函数，返回true表示选定的对象
template <typename Item>
template <typename Predicate>
bool MyStorage<Item>::Modify(Predicate pre, bool is_handle_first)
{
    
    ForeachMutable([&](Item& item) -> bool {
        return pre(item);
    }, is_handle_first);

    return 0;
}


template <typename Item>
template <typename Predicate>
bool MyStorage<Item>::Find(Predicate pre)
{
    bool found = false;

    ForeachReadOnly([&](const Item& item) -> bool{
        if (pre(item)) {
            found = true;
            return true;
        }
        return false;
    });

    return found;
}

/// @brief 清空存储（包括NVS）
template <typename Item>
bool MyStorage<Item>::Clear()
{
    InvalidAllCache();
    auto err = storage_.Clear();
    return err == ESP_OK;
}